
package keul.planner.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;

/**
 * Diese Entity repräsentiert einen Haltepunkt mit verschiedenen
 * benachbarten Punkten; eine X- und Y-Koordinate deuten eine
 * Position auf einer Karte an; dazu ein Name und Id.
 * @author kev
 */
@Entity
public class Station implements Serializable, Comparable
{
    
    private static final long serialVersionUID = 1L;
    static final double EARTHS_RADIUS = 6371; // km
    
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @ManyToMany
    private List<Station> neighbors;
    @ManyToOne(cascade= CascadeType.DETACH)
    private City city;
    private String name;
    private float stationLatitude;
    private float stationLongitude;
    
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public City getCity() {
        return city;
    }
    public void setCity(City city) {
        this.city = city;
    }
    public List<Station> getNeighbors() {
        return neighbors;
    }
    public void setNeighbors(Station[] neighbors) {
        this.neighbors.addAll(Arrays.asList(neighbors));
    }
    public void setNeighbors(List<Station> neighbors) {
        this.neighbors = neighbors;
    }
    public float getStationLatitude() {
        return stationLatitude;
    }
    public void setStationLatitude(float stationLatitude) {
        this.stationLatitude = stationLatitude;
    }
    public float getStationLongitude() {
        return stationLongitude;
    }
    public void setStationLongitude(float stationLongitude) {
        this.stationLongitude = stationLongitude;
    }
    
    public boolean isStationServedBy(Line line)  {
        for (Station station : line.getStops()) {
            if (station.equals(this))
                return true;
        }
        return false;
    }
    
    public Station(City city) {
        this.city = city;
        this.name = city.getName();
        this.stationLatitude = city.getLatitude();
        this.stationLongitude = city.getLongitude();
        this.neighbors = new ArrayList<Station>();
    }  
    public Station(City city, String stationName) {
        this(city, stationName, city.getLatitude(), city.getLongitude());
    }  
    public Station(City city, String stationName, float stationLatitude, float staionLongitude) {
        this.city = city;
        this.stationLatitude = stationLatitude;
        this.stationLongitude = staionLongitude;
        this.name = stationName;
        this.neighbors = new ArrayList<Station>();
    }  
    public Station(String name) {
        this.name = name;
        this.neighbors = new ArrayList<Station>();
    }  
    public Station() {
        this("");
    }
    
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }
    
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Station)) {
            return false;
        }
        Station other = (Station) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return name;
    }
    /**
     * ausführliche toString()-Methode
     * @return 
     */
    public String oldToString() {
        StringBuffer sb = new StringBuffer();
        sb.append(
                "kev.entities.Station[ id=")     .append(id)     
                .append(", name=\"")             .append(name)   
                .append(", city=(")              .append(city)        
                .append(") stationLatitude=")    .append(stationLatitude)
                .append(", stationLongitude=")   .append(stationLongitude)
                .append(", neighbors[]={");
        int iCount=neighbors.size();
        for (Station station : neighbors) {
            sb.append(station.getName());
            if(--iCount!=0)
                sb.append(", ");            
        }
        sb.append("} ] \n");
        return sb.toString();
    }
    
    /**
     * 
     * @author Lüder
     * @param s1
     * @param s2
     * @return 
     */
    public static double computeGeoDistance(Station s1, Station s2) {
        if (s1 == null || s2 == null) {
            return 0.0;
        } else {
            double dLat = Math.toRadians(s2.stationLatitude - s1.stationLatitude);
            double dLon = Math.toRadians(s2.stationLongitude - s1.stationLongitude);
            double lat1 = Math.toRadians(s1.stationLatitude);
            double lat2 = Math.toRadians(s2.stationLatitude);

            double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
                    + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
            double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
            return EARTHS_RADIUS * c;
        }
     }
    
    /**
     * Gibt true bei Vorhandensein eines Haltepunkts
     * dieser Station auf einer übergebenen Linie.
     * @author kev
     * @param line
     * @return 
     */
    public boolean isServedBy(Line line) {
        for (Station station : line.getStops())
            if (station.equals(this))
                return true;
        return false;
    }

    @Override
    public int compareTo(Object o) {
        if (o instanceof Station)
            return name.compareTo(((Station)o).getName());
        return 0;
    }
    
}
